//
//  UIView_runtime.swift
//  MyLibrary
//
//  Created by 周博 on 2020/6/17.
//  Copyright © 2020 ncit. All rights reserved.
//

import UIKit

private var gradientBorderWidth_key = "gradientBorderWidth_key"
private var gradientColors_key = "gradientColors_key"
private var gradientBorderView_key = "gradientBorderView_key"
private var gradientCornerRadius_key = "gradientCornerRadius_key"

private var gradientBaseView_key = "gradientBaseView_key"
private var gradientBaseViewColors_key = "gradientBaseViewColors_key"


private var gradientBaseView_startPoint_Key = "gradientBaseView_startPoint_Key"
private var gradientBaseView_endPoint_Key = "gradientBaseView_endPoint_Key"


public extension UIView {
    
    
    // MARK: 方法交换
    
    public override class func initRunTime() {
        exchange(originalSelector: #selector(awakeFromNib), swizzledSelector: #selector(exchange_awakeFromNib))
        exchange(originalSelector: #selector(layoutSubviews), swizzledSelector: #selector(exchange_layoutSubviews))
    }



    
    
    /**
    * 1. UIView和UILabel的awakeFromXib如果同时被交换, 则两个交换的方法都会执行
    * 2. 父类的运行时交换方法永远都会被执行, (可以在父类中判断类型, 截断子类)
    * 3. 如果父类的运行时方法有交换, 子类不需要重新交换, 因为重新交换也不能截断父类, 可以override重写父类的交换方法, 在里面做自己的事情
    * 4. 子类重写父类的交换方法, 不能调用self.exchange_xxx, 会导致死循环, 要super.exchange_xxx, 父类使用classForCoder判断, 理论上不让super代码在子类中执行
    * 5. 处理方法:
        1. 如果是类似awakeFromXib方法需要交换, 不需要子类重写, 直接在UIView的交换方法中判断class类型, 做相应的处理即可
        2. 子类重写, 调用super, 如果需要防止super自身的对于uiview的处理也被执行, 可以添加类型判断, 如果不需要截断, 就不需要
    */
    @objc func exchange_awakeFromNib() {

        exchange_awakeFromNib()

//        if self.classForCoder == UIView.classForCoder() {
//
//            // uiview的处理
//            print("UIView awake处理")
//        } else if self is UILabel {
//
//            // a is class, 类似于oc的isKindOf
//            // uilabel处理
//            print("UILabel awake处理")
//
//        } else if self is UITableView {
//
//            print("UITableView awake处理")
//
//
//        } else if self is UITableViewCell {
//
//            print("UITableViewCell awake处理")
//        }
    }
    
    
    
    
    
    @objc func exchange_layoutSubviews() {
        
        
//        print("layouts ubviews: \(self)")

        if !(self is UIButton) {
            
            exchange_layoutSubviews()
            
//            // 添加渐变边框
//            if self.gradientBorderColors != nil && gradientBorderWidth != 0 {
//
//                gradientBorderView.superview?.sendSubviewToBack(gradientBorderView)
//                gradientBorderView.gradientColor(colors: gradientBorderColors!)
//                gradientBorderView.frame = self.gradientBorderFrame
//            }
            
            // 使用创建view的方式添加渐变背景
            if let gradientBaseView = self.gradientBaseView, let _ = self.gradientBaseViewColors {
                gradientBaseView.superview?.sendSubviewToBack(gradientBaseView)
                
                gradientBaseView.frame = self.bounds
                gradientBaseView.gradientColor(startPoint: gradientBaseView_startPoint, endPoint: gradientBaseView_endPoint, colors: self.gradientBaseViewColors!)
                
            }
        }

    }
    
    
    
    
    /**
     * 设置渐变背景色的时候, layoutsubviews会无限调用, 而且不崩溃, 导致性能严重损耗
     */

    
    
    // MARK: 设置渐变边框
    
    /** 渐变边框宽度, 默认宽度1 */
    var gradientBorderWidth: CGFloat {
        get {
            if let a = objc_getAssociatedObject(self, &gradientBorderWidth_key) as? CGFloat {
                return a
            }
            return 1
        }
        set {
            
            // zwarning: OBJC_ASSOCIATION_ASSIGN 使用这个坑逼, 不能正确存储
            objc_setAssociatedObject(self, &gradientBorderWidth_key, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    
    /**
     * 渐变边框颜色
     */
    var gradientBorderColors: [CGColor]? {
        get {
            if let a = objc_getAssociatedObject(self, &gradientColors_key) as? [CGColor] {
                return a
            }
            return nil
        }
        set {
            
            // zwarning: OBJC_ASSOCIATION_ASSIGN 使用这个坑逼, 不能正确存储
            objc_setAssociatedObject(self, &gradientColors_key, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
            
            // 延迟创建 (保证在layoutsubviews之后执行), 如果这段代码有问题, 放在layoutsubviews里, 放在这里主要是为了防止在layoutsubviews里面重复渲染导致性能浪费
            DispatchQueue.main.async { [unowned self] in
                gradientBorderView.superview?.sendSubviewToBack(gradientBorderView)
                gradientBorderView.gradientColor(colors: gradientBorderColors!)
                gradientBorderView.frame = self.gradientBorderFrame
            }
        }
    }
    
    /**
     * 渐变边框圆角
     */
    var gradientBorderCornerRadius: CGFloat {
        get {
            if let a = objc_getAssociatedObject(self, &gradientCornerRadius_key) as? CGFloat {
                return a
            }
            return 0
        }
        set {
            
            // zwarning: OBJC_ASSOCIATION_ASSIGN 使用这个坑逼, 不能正确存储
            objc_setAssociatedObject(self, &gradientCornerRadius_key, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }

    
    /**
     * 渐变边框控件
     */
    private var gradientBorderView: UIView {
        get {
            if let a = objc_getAssociatedObject(self, &gradientBorderView_key) as? UIView {
                return a
            } else {
                
                let view = UIView()
                self.gradientBorderView = view
                
                if let superview = self.superview {
                    superview.addSubview(view)
                } else {
                    self.addSubview(view)
                }
                
                view.cornerRadius = self.gradientBorderCornerRadius
                return view
            }
        }
        set {
            
            // zwarning: OBJC_ASSOCIATION_ASSIGN 使用这个坑逼, 不能正确存储
            objc_setAssociatedObject(self, &gradientBorderView_key, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }

    
    var gradientBorderFrame: CGRect {
        return CGRect(x: self.x - gradientBorderWidth, y: self.y - gradientBorderWidth, width: self.width + 2*gradientBorderWidth, height: self.height + 2*gradientBorderWidth)
    }
    
    

    

    
    
    // MARK: 添加背景渐变view
    
    /** 渐变色view */
    private var gradientBaseView: UIView? {
        get {
            if let a = objc_getAssociatedObject(self, &gradientBaseView_key) as? UIView {
                return a
            } else {
                return nil
            }
        }
        set {
            
            // zwarning: OBJC_ASSOCIATION_ASSIGN 使用这个坑逼, 不能正确存储
            objc_setAssociatedObject(self, &gradientBaseView_key, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    
    /** 渐变色view的颜色 */
    var gradientBaseViewColors: [CGColor]? {
        get {
            if let a = objc_getAssociatedObject(self, &gradientBaseViewColors_key) as? [CGColor] {
                return a
            } else {
                return nil
            }
        }
        set {
            
            // zwarning: OBJC_ASSOCIATION_ASSIGN 使用这个坑逼, 不能正确存储
            objc_setAssociatedObject(self, &gradientBaseViewColors_key, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }


    /** 渐变色的startPoint */
    var gradientBaseView_startPoint: CGPoint {
        get {
            if let a = objc_getAssociatedObject(self, &gradientBaseView_startPoint_Key) as? CGPoint {
                return a
            }
            return CGPoint(x: 0, y: 0)
        }
        set {
            
            // zwarning: OBJC_ASSOCIATION_ASSIGN 使用这个坑逼, 不能正确存储
            objc_setAssociatedObject(self, &gradientBaseView_startPoint_Key, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    
    
    /** 渐变色的endtPoint */
    var gradientBaseView_endPoint: CGPoint {
        get {
            if let a = objc_getAssociatedObject(self, &gradientBaseView_endPoint_Key) as? CGPoint {
                return a
            }
            return CGPoint(x: 1, y: 1)
        }
        set {
            
            // zwarning: OBJC_ASSOCIATION_ASSIGN 使用这个坑逼, 不能正确存储
            objc_setAssociatedObject(self, &gradientBaseView_endPoint_Key, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    
    
    
    
    
    func addBG_gradientView(colors: [CGColor], startPoint: CGPoint = CGPoint(x: 0, y: 0), endPoint: CGPoint = CGPoint(x: 1, y: 1)) {
        
        if self.gradientBaseView == nil {
            self.gradientBaseView = UIView()
            self.addSubview(gradientBaseView!)
            
            self.gradientBaseViewColors = colors
            self.gradientBaseView_startPoint = startPoint
            self.gradientBaseView_endPoint = endPoint
        }
    }
    
    

    
}


public extension UIView {
    
    
    /**
     * 添加背景色快速设置, 格式 "#123456_0.40"
     */
    @IBInspectable var diy_bgColor: String {
        get {
            return ""
        }
        set {
            self.backgroundColor = colorWith(xibString: newValue) ?? UIColor.white
        }
    }
    
    /** 圆角 */
    @IBInspectable var cornerRadius: CGFloat {
        get {
            return self.layer.cornerRadius
        }
        set {
            self.layer.cornerRadius = newValue
            self.layer.masksToBounds = true
        }
    }

    /**
     * 圆角截取的方法必须在view确定size之后设置, 建议写在layoutSubViews里面
     */
    func cornerBounds(radius: CGFloat, byRoundingCorners: UIRectCorner = [.topLeft, .topRight, .bottomLeft, .bottomRight]) {
        let path = UIBezierPath(roundedRect: self.bounds,
                                byRoundingCorners: byRoundingCorners,  // 通过这个参数可以单独控制四个圆角
                                cornerRadii: CGSize(width: radius, height: radius))
        let shapeLayer = CAShapeLayer()
        shapeLayer.frame = self.bounds
        shapeLayer.path = path.cgPath
        self.layer.mask = shapeLayer
    }
    
    
    /** 从xib或者sb设置中获取color */
    func colorWith(xibString: String) -> UIColor? {
        
        let string = xibString as NSString
        
        if xibString == XibColor.white.rawValue {
            return UIColor.white
        } else if xibString == XibColor.clear.rawValue {
            return UIColor.clear
        } else if xibString == XibColor.black.rawValue {
            return UIColor.black
        }
        
        
        if (string.length == 7 || string.length == 9) && string.hasPrefix("#") {
            
            // 没有设置透明度, 默认为1
            // "#ffffff" "#123456"格式
            return UIColor.init(hexString: string as String)
            
        } else if string.substring(with: NSMakeRange(0, 1)) == "#" {
            
            if string.substring(with: NSMakeRange(7, 1)) == "_" {
                // 设置了透明度
                // "#ffffff_0.1" "#123456_0.15"格式
                let colorString = string.substring(with: NSMakeRange(0, 7))
                let textColor = UIColor.init(hexString: colorString)
                
                let colorAlpha = string.substring(with: NSMakeRange(8, string.length - colorString.count - 1))
                let newColor = textColor.withAlphaComponent(CGFloat(Double(colorAlpha) ?? 0.5))
                
                return newColor
            } else if string.substring(with: NSMakeRange(9, 1)) == "_"  {
                
                // 设置了透明度
                // "#ffffff_0.1" "#123456_0.15"格式
                let colorString = string.substring(with: NSMakeRange(0, 9))
                let textColor = UIColor.init(hexString: colorString)
                
                let colorAlpha = string.substring(with: NSMakeRange(10, string.length - colorString.count - 1))
                let newColor = textColor.withAlphaComponent(CGFloat(Double(colorAlpha) ?? 0.5))
                
                return newColor
            }

            
        } else if string.hasPrefix(whiteString) {
            
            var color = UIColor.white

            if string.length > whiteString.count {
                let colorAlpha = string.substring(with: NSMakeRange(whiteString.count, string.length - whiteString.count))
                
                let alpha = CGFloat(Double(colorAlpha) ?? 1)
                color = color.withAlphaComponent(alpha)
            }
            
            return color
        }
        
        return nil
    }
}


/**
 * 添加渐变边框
 */
public extension UIView {
    
    func addGradientBorder(width: CGFloat = 1, colors: [CGColor], cornerRadius: CGFloat) {
        self.gradientBorderColors = colors
        self.gradientBorderWidth = width
        self.gradientBorderCornerRadius = cornerRadius
    }
}

